﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Yelper.API;
using System.Security.Cryptography;
using System.Text;
using System.Security.Principal;


namespace Yelper.API {
    public class BasicAuthenticationModule : IHttpModule {
        private static UnicodeEncoding enc = new UnicodeEncoding();
        private static SHA384Managed sha = new SHA384Managed();

        public void Init(HttpApplication context) {
            context.AuthenticateRequest += new EventHandler(context_AuthenticateRequest);
        }

        private void context_AuthenticateRequest(object sender, EventArgs e) {
            var context = (sender as HttpApplication).Context;

            /* Does the http request contains an Authorization header? */
            if (context.Request.Headers.AllKeys.Contains("Authorization")) {
                context.User = GetPrincipal(HttpContext.Current.Request.Headers["Authorization"]);
            } else {
                context.User = new GenericPrincipal(new GenericIdentity(""), new string[] { });
            }
        }

        /// <summary>
        /// Hashes an string using SHA-384
        /// </summary>
        /// <param name="text">The string that needs to be hashed</param>
        /// <returns>The SHA-384 hashed string</returns>
        private static byte[] StringToSHA384(string text) {
            return sha.ComputeHash(enc.GetBytes(text));
        }
       
        private static IPrincipal GetPrincipal(string authHeader) {
            var creds = ParseAuthHeader(authHeader);

            /* An error occured while parsing the authentication header */
            if (creds == null)
                return null;

            /* Retrieve the user from the database */
            using (var db = new YelperEntities()) {
                var pwd = StringToSHA384(creds[1]);
                var uname = creds[0];
                var user = (from u in db.Users
                            where u.Username == uname && u.Activated
                            select u).SingleOrDefault();
                if (user != null && user.UserDetail.Password.SequenceEqual(pwd))
                    return new GenericPrincipal(new GenericIdentity(creds[0]), new string[] { });
                else
                    return new GenericPrincipal(new GenericIdentity(""), new string[] { });
            }
        }

        private static string[] ParseAuthHeader(string authHeader) {
            if (authHeader == null || authHeader.Length == 0 || !authHeader.StartsWith("Basic"))
                return null;
            var base64Credentials = authHeader.Substring(6);
            var credentials = Encoding.ASCII.GetString(Convert.FromBase64String(base64Credentials)).Split(new char[] { ':' });
            if (credentials.Length != 2 || string.IsNullOrEmpty(credentials[0]) || string.IsNullOrEmpty(credentials[0]))
                return null;
            return credentials;
        }

        public void Dispose() { }
    }
}